package xyz.mimai.media.netty.simple;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.util.CharsetUtil;

import java.nio.charset.Charset;

/**
 * @ClassName Server
 * @Description 基于netty的简单的服务端
 * @Author 方丈
 * @Date 2021/2/3 17:20
 * @Version 1.0.0
 **/
public class Server {
    public static void main(String[] args) {
        //创建主线程组，只处理连接请求
        EventLoopGroup eventBossGroup = new NioEventLoopGroup(2) ;
        //创建工作线，接收主线程分发过来的任务，完成实际的工作                                                                                                                   程组
        EventLoopGroup eventWorkGroup = new NioEventLoopGroup(8) ;

        //创建一个服务器端的启动对象
        ServerBootstrap serverBootstrap = new ServerBootstrap();

        //设置服务器的配置
        serverBootstrap.group(eventBossGroup,eventWorkGroup)
                .channel(NioServerSocketChannel.class)
                //ChannelOption.SO_BACKLOG对应的是tcp/ip协议listen函数中的backlog参数，
                //服务端处理客户端连接请求是顺序处理的，同一时间只能处理一个客户端连接，
                //多个客户端来的时候，服务端将不能处理的客户端连接请求放在队列中等待处理，backlog参数指定了队列的大小
                .option(ChannelOption.SO_BACKLOG,128)
                //Channeloption.SO_KEEPALIVE参数对应于套接字选项中的SO_KEEPALIVE，该参数用于设置TCP连接。
                //当设置该选项以后，如果在两小时内没有数据的通信时，TCP会自动发送一个活动探测数据报文。
                .childOption(ChannelOption.SO_KEEPALIVE,true)
                .childHandler(new ChannelInitializer<SocketChannel>() {  //为eventWorkGroup相关联的管道（pipeline）设置处理器

                    //指定业务处理的自定义handler
                    @Override
                    protected void initChannel(SocketChannel socketChannel) throws Exception {
                        socketChannel.pipeline().addLast(new SelfDefineServerHandler());
                    }
                });

        System.out.println("简单服务端初始化成功，服务中... ...");
        try {
            ChannelFuture channelFuture = serverBootstrap.bind(7777).sync();
            channelFuture.channel().closeFuture().sync();
        }catch (InterruptedException ine){
            ine.printStackTrace();
        }finally {
            eventBossGroup.shutdownGracefully();
            eventWorkGroup.shutdownGracefully();
        }

    }


    /**
     * 自定义业务处理
     */
    public static class SelfDefineServerHandler extends ChannelInboundHandlerAdapter{

        /**
         * @description  必须将消息编码，否则无法发送
         * @author 方丈
         * @date 2021-02-04 10:14
         * @param	nativeMsg
         * @return io.netty.buffer.ByteBuf
         * @since 1.0.0
         */
        private ByteBuf buildNettyMsg(String nativeMsg){
            return Unpooled.copiedBuffer(nativeMsg, CharsetUtil.UTF_8);
        }

        private void doSomeWork(ChannelHandlerContext ctx,Object msg){
            ByteBuf bb =(ByteBuf) msg;
            String recvContent  = bb.toString(Charset.forName("utf-8"));
            System.out.println("接收到了"+ctx.channel().remoteAddress()+"的消息："+recvContent);
            System.out.println("做一些业务处理的工作... ...");
        }

        @Override
        public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
     //       super.channelRead(ctx, msg);
            doSomeWork(ctx,msg);
        }

        @Override
        public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
          //  super.channelReadComplete(ctx);
            String respMsg ="你好，"+ctx.channel().remoteAddress()+ "，数据接收完毕，业务处理成功";
            ctx.channel().writeAndFlush(buildNettyMsg(respMsg));
        }

        @Override
        public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
       //     super.exceptionCaught(ctx, cause);
            System.out.println("发生了异常... ...");
            cause.printStackTrace();
            ctx.close();
        }
    }
}
